﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="BindingEvaluator.cs" company="JDML Consulting Ltd.">
//   Copyright 2011 Photon Project - http://photon.codeplex.com
// </copyright>
// <summary>
//   
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace Photon.Windows
{
    using System.Windows;
    using System.Windows.Data;

    public class BindingEvaluator<T> : FrameworkElement
    {
        public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(T),
            typeof(BindingEvaluator<T>), new PropertyMetadata(default(T), NotifyValueChanged));

        public BindingEvaluator()
        {
        }

        public BindingEvaluator(Binding binding)
        {
            SetBinding(ValueProperty, binding);
        }

        public BindingEvaluator(string bindingPath)
        {
            SetBinding(ValueProperty, new Binding(bindingPath));
        }

        public T Value
        {
            get { return (T)GetValue(ValueProperty); }
            set { SetValue(ValueProperty, value); }
        }

        public Binding ValueBinding
        {
            get
            {
                var expression = GetBindingExpression(ValueProperty);
                return expression != null ? expression.ParentBinding : null;
            }
            set
            {
                SetBinding(ValueProperty, value);
            }
        }

        private static void NotifyValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((BindingEvaluator<T>)d).OnValueChanged(e.OldValue, e.NewValue);
        }

        private void OnValueChanged(object oldValue, object newValue)
        {
            if (ValueChanged != null)
            {
                ValueChanged(this, new RoutedPropertyChangedEventArgs<T>((T)oldValue, (T)newValue));
            }
        }

        public T GetValueFromContext(object target, Binding valueBinding)
        {
            var restoreValueBinding = ValueBinding;
            if (restoreValueBinding != valueBinding)
            {
                ValueBinding = valueBinding;
            }
            var result = GetValueFromContext(target);
            if (restoreValueBinding != valueBinding)
            {
                ValueBinding = restoreValueBinding;
            }
            return result;
        }

        public T GetValueFromContext(object target)
        {
            var dataContext = DataContext;
            if (dataContext != target)
            {
                DataContext = target;
            }

            var result = Value;
            if (dataContext != target)
            {
                DataContext = dataContext;
            }

            return result;
        }

        public event RoutedPropertyChangedEventHandler<T> ValueChanged;
    }
}